package com.benmei.weike.service.weixin;

import com.benmei.weike.common.MyPage;
import com.benmei.weike.dao.weixin.WeixinUserInfoDao;
import com.benmei.weike.entity.weixin.WeixinTwoDimensionalCode;
import com.benmei.weike.entity.weixin.WeixinUserInfo;
import com.benmei.weike.exception.ServerException;
import com.benmei.weike.rest.dto.ReceiveAccessTokenDto;
import com.benmei.weike.rest.dto.WeixinUserInfoDto;
import com.benmei.weike.util.HttpUtil;
import com.benmei.weike.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author Peter
 */
// Spring Service Bean的标识.
@Component
public class WeixinUserInfoService {

    private static Logger logger = LoggerFactory.getLogger(WeixinUserInfoService.class);

    @Autowired
    private WeixinOAuthService weixinOauthService;

    @Autowired
    private WeixinAccessTokenService weixinAccessTokenService;

    @Autowired
    private WeixinUserInfoDao weixinUserInfoDao;

    @Autowired
    private WeixinConf weixinConf;

    @Autowired
    private WeixinTwoDimensionalCodeService weixinTwoDimensionalCodeService;

    public WeixinUserInfo getById(Long id) {
        return weixinUserInfoDao.getById(id);
    }

    public List<WeixinUserInfo> getAll() {
        return weixinUserInfoDao.getAll();
    }

    /**
     * 分页查询
     *
     * @param pageSize
     * @return
     */
    public MyPage<WeixinUserInfo> searchPage(WeixinUserInfo weixinUserInfo, int currentPage, int pageSize) {
        MyPage<WeixinUserInfo> myPage = new MyPage<WeixinUserInfo>();

        Long count = weixinUserInfoDao.searchCount(weixinUserInfo);

        int pageStart = (currentPage - 1) < 0 ? 0 : (currentPage - 1) * pageSize;
        List<WeixinUserInfo> list = weixinUserInfoDao.searchPage(weixinUserInfo, pageStart, pageSize);

        myPage.setCount(count);
        myPage.setContent(list);

        return myPage;
    }

    public void save(WeixinUserInfo weixinUserInfo) {
        weixinUserInfoDao.save(weixinUserInfo);
    }

    public void update(WeixinUserInfo weixinUserInfo) {
        weixinUserInfoDao.update(weixinUserInfo);
    }

    /**
     * 软删除
     */
    public void delete(Long id) {
        weixinUserInfoDao.delete(id);
    }

    // 拉取用户信息，并保存, 返回openId
    public String receiveWeixinUserInfo(String code) {

        //第二步：通过code换取网页授权access_token
        ReceiveAccessTokenDto receiveAccessTokenDto = weixinOauthService.receiveAccessToken(code);
        if (StringUtils.isNotBlank(receiveAccessTokenDto.getErrcode())) {
            logger.error("拉取 AccessToken 失败！---->>{code:" + code + ",errorCode:" + receiveAccessTokenDto.getErrcode() + ",errorMsg:" + receiveAccessTokenDto.getErrmsg() + "}");
            throw new ServerException("获取access_token失败");
        } else {

            //第四步：拉取用户信息(需scope为 snsapi_userinfo) ， 根据 Access_Token 从微信服务器拉取用户信息
            WeixinUserInfoDto weixinUserInfoDto = weixinOauthService.receiveWeixinUserInfo(receiveAccessTokenDto.getAccess_token(), receiveAccessTokenDto.getOpenid());

            if (weixinUserInfoDto == null || StringUtils.isNotBlank(weixinUserInfoDto.getErrcode())) {
                logger.error("拉取用户信息失败！ request parameter -->> {access_token:" + receiveAccessTokenDto.getAccess_token() + ",openid:" + receiveAccessTokenDto.getOpenid()
                        + "} result -->> {errorCode:" + weixinUserInfoDto.getErrcode() + ",errorMsg:" + weixinUserInfoDto.getErrmsg() + "}");
                throw new ServerException("获取用户信息失败");
            } else {

                WeixinUserInfo weixinUserInfo = dtoToEntity(weixinUserInfoDto);

                weixinUserInfo.setUpdateDate(new Date());

                // 如果数据库中已经有userinfo--更新，否则新增
                WeixinUserInfo old = weixinUserInfoDao.getByOpenId(weixinUserInfo.getOpenid());
                if (old != null) {
                    //更新微信用户信息
                    weixinUserInfo.setId(old.getId());
                    weixinUserInfoDao.update(weixinUserInfo);
                } else {
                    //新增微信用户信息
                    weixinUserInfo.setWeixinPublicId(weixinConf.getPublicId());
                    weixinUserInfo.setCreateDate(new Date());
                    weixinUserInfoDao.save(weixinUserInfo);
                }
            }

        }

        return receiveAccessTokenDto.getOpenid();
    }

    /**
     * 根据openId获取用微信信息<br/>
     * 如果该用户信息不存在会从微信服务器拉取用户信息
     *
     * @param openId
     * @return
     * @throws ServerException
     */
    public WeixinUserInfo receiveWeixinUserInfoByOpenId(String openId) {
        WeixinUserInfo userInfo = weixinUserInfoDao.getByOpenId(openId);
        if (userInfo == null) {
            String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + weixinAccessTokenService.getAccessToken() + "&openid=" + openId + "&lang=zh_CN";
            String body = HttpUtil.httpGet(url);
            WeixinUserInfoDto dto = null;
            try {
                dto = JsonUtil.toObject(body, WeixinUserInfoDto.class);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
                throw new ServerException("获取用户信息错误，数据格式错误");
            }

            userInfo = dtoToEntity(dto);
            userInfo.setCreateDate(new Date());
            userInfo.setUpdateDate(new Date());
            weixinUserInfoDao.save(userInfo);
        }

        return userInfo;
    }


    private WeixinUserInfo dtoToEntity(WeixinUserInfoDto dto) {
        WeixinUserInfo info = new WeixinUserInfo();
        info.setCity(dto.getCity());
        info.setCountry(dto.getCountry());
        info.setHeadimgurl(dto.getHeadimgurl());

        info.setLanguage(dto.getLanguage());
        info.setNicknameForBase64Encoder(dto.getNickname());//解决msyql插入不进Emoji表情问题。--->>  mysql中的utf8mb4字符集可以插入表情
//        info.setNickname(dto.getNickname());
        info.setOpenid(dto.getOpenid());
        info.setPrivilege(StringUtils.join(dto.getPrivilege(), ","));
        info.setProvince(dto.getProvince());
        info.setSex(dto.getSex());
        info.setUnionid(dto.getUnionid());

        return info;
    }

    public WeixinUserInfo getByOpenIdAndWeixinPublicId(String openId, Long publicId) {
        return weixinUserInfoDao.getByOpenIdAndWeixinPublicId(openId, publicId);
    }

    public WeixinUserInfo getByOpenid(String openId) {
        return getByOpenIdAndWeixinPublicId(openId, weixinConf.getPublicId());
    }

}
